package com.bcmusic.search.service.impl;

import com.alibaba.fastjson.JSON;
import com.bcmusic.music.pojo.Music;
import com.bcmusic.search.service.ESService;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.support.WriteRequest;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.client.indices.GetIndexRequest;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

import javax.naming.directory.SearchResult;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @ClassName : ESServiceImpl  //类名
 * @Description :   //描述
 * @Author : YG  //作者
 * @Date: 2020-10-26 10:12  //时间
 */

/**
 * 赶工，后面再封装
 */
@Service
public class ESServiceImpl implements ESService {

    @Autowired
    private RestHighLevelClient client;

    @Override
    public List<Map<String, Object>> getCopyright(Integer musicId) throws Exception {
        SearchRequest request1 = new SearchRequest("authorization");
        //构建搜索条件
        SearchSourceBuilder builder = new SearchSourceBuilder();
        //按照颜色查询方法，其中keyword表示不分词匹配，把该词当成一个整体
        //QueryBuilders.matchQuery()表示模糊查询
        //QueryBuilders.termQuery()表示精确查询
        //多条件查询
//            BoolQueryBuilder must = QueryBuilders.boolQuery().must(QueryBuilders.matchQuery("item_color.keyword", req.getItem_color()))
//                    .must(QueryBuilders.matchQuery("item_brand.keyword", req.getItem_brand()));

        //条件判断，如果传入的属性为空的话则不执行该查询条件
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        boolQueryBuilder.must(QueryBuilders.matchQuery("musicId", musicId));

        //QueryBuilders.boolQuery().should(QueryBuilders.matchQuery()).should()
        //单条件查询
//            MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery("item_color.keyword", req.getItem_color());
        builder.query(boolQueryBuilder);

        builder.timeout(new TimeValue(60, TimeUnit.SECONDS));

        request1.source(builder);
        SearchResponse searchResponse = client.search(request1, RequestOptions.DEFAULT);

        //解析结果
        ArrayList<Map<String, Object>> list = new ArrayList<>();
        for (SearchHit hit : searchResponse.getHits().getHits()) {
            Map<String, HighlightField> highlightFields = hit.getHighlightFields();
            Map<String, Object> sourceAsMap = hit.getSourceAsMap();  //没高亮的数据
            list.add(sourceAsMap);
        }
        return list;
    }

    /**
     * 不想封装了，就这样吧
     * @param musicName
     * @param singer
     * @param lyricist
     * @param composer
     * @return
     * @throws Exception
     */
    @Override
    public List<Map<String, Object>> getMusic(String musicName,String singer,String lyricist,String composer) throws Exception {
        SearchRequest request1 = new SearchRequest("music");
        //构建搜索条件
        SearchSourceBuilder builder = new SearchSourceBuilder();
        //按照颜色查询方法，其中keyword表示不分词匹配，把该词当成一个整体
        //QueryBuilders.matchQuery()表示模糊查询
        //QueryBuilders.termQuery()表示精确查询
        //多条件查询
//            BoolQueryBuilder must = QueryBuilders.boolQuery().must(QueryBuilders.matchQuery("item_color.keyword", req.getItem_color()))
//                    .must(QueryBuilders.matchQuery("item_brand.keyword", req.getItem_brand()));

        //条件判断，如果传入的属性为空的话则不执行该查询条件
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        boolQueryBuilder.should(QueryBuilders.matchQuery("musicName", musicName));
        boolQueryBuilder.should(QueryBuilders.matchQuery("singer", singer));
        boolQueryBuilder.should(QueryBuilders.matchQuery("lyricist", lyricist));
        boolQueryBuilder.should(QueryBuilders.matchQuery("composer", composer));


        //QueryBuilders.boolQuery().should(QueryBuilders.matchQuery()).should()
        //单条件查询
//            MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery("item_color.keyword", req.getItem_color());
        builder.query(boolQueryBuilder);

        builder.timeout(new TimeValue(60, TimeUnit.SECONDS));

        //高亮显示
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        highlightBuilder.field("musicName").field("singer").field("lyricist").field("composer");
        highlightBuilder.requireFieldMatch(true);  //多个单词高亮的话，要把这个设置为trues
        highlightBuilder.preTags("<span style='color:red'>");
        highlightBuilder.postTags("</span>");
        builder.highlighter(highlightBuilder);

        request1.source(builder);
        SearchResponse searchResponse = client.search(request1, RequestOptions.DEFAULT);

        //解析结果
        ArrayList<Map<String, Object>> list = new ArrayList<>();
        for (SearchHit hit : searchResponse.getHits().getHits()) {

            Map<String, HighlightField> highlightFields = hit.getHighlightFields();
            HighlightField musicNameHigh = highlightFields.get("musicName");
            Map<String, Object> sourceAsMap = hit.getSourceAsMap();  //没高亮的数据
            if (musicNameHigh    != null) {
                Text[] fragments = musicNameHigh.fragments();
                String n_musicName = "";
                for (Text text : fragments) {
                    n_musicName += text;
                }
                sourceAsMap.put("musicName", n_musicName);   //把高亮字段替换掉原本的内容即可
            }

            HighlightField singerHigh = highlightFields.get("singer");
            if (singerHigh != null) {
                Text[] fragments = singerHigh.fragments();
                String n_singer = "";
                for (Text text : fragments) {
                    n_singer += text;
                }
                sourceAsMap.put("singer", n_singer);   //把高亮字段替换掉原本的内容即可
            }

            HighlightField composerHigh = highlightFields.get("composer");
            if (composerHigh != null) {
                Text[] fragments = composerHigh.fragments();
                String n_composer = "";
                for (Text text : fragments) {
                    n_composer += text;
                }
                sourceAsMap.put("composer", n_composer);   //把高亮字段替换掉原本的内容即可
            }

            HighlightField lyricistHigh = highlightFields.get("lyricist");
            if (lyricistHigh != null) {
                Text[] fragments = lyricistHigh.fragments();
                String n_lyricist = "";
                for (Text text : fragments) {
                    n_lyricist += text;
                }
                sourceAsMap.put("lyricist", n_lyricist);   //把高亮字段替换掉原本的内容即可
            }
            list.add(sourceAsMap);
        }
        return list;
    }



    /**
     * 批量存储
     * @param indexName
     * @param itemVOList
     */
    @Override
    public void bulkSave(String indexName, List<?> itemVOList) {
        // 批量插入请求
        BulkRequest bulkRequest = new BulkRequest();
        bulkRequest.timeout("10m");
        // 写入完成立即刷新，否则会有延时，前端获取不到数据
        bulkRequest.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE);
        itemVOList.forEach(itemVO -> {
            IndexRequest indexRequest = new IndexRequest(indexName);
            indexRequest.source(JSON.toJSONString(itemVO), XContentType.JSON);
            bulkRequest.add(indexRequest);
        });
        try {
            client.bulk(bulkRequest, RequestOptions.DEFAULT);
        } catch (IOException e) {
            System.out.println("---批量插入ES失败---");
            e.printStackTrace();
        }
    }


    /**
     * 创建索引，我手动调用
     * @param indexName
     * @return
     */
    @Override
    public boolean createItemIndex(String indexName) {
        // 判断索引是否存在，存在就先删除
        if (isIndexExist(indexName)) {
            deleteIndex(indexName);
        }
        // 创建索引请求
        CreateIndexRequest indexRequest = new CreateIndexRequest(indexName);
        // 可选参数，备份2，碎片3
        indexRequest.settings(Settings.builder()
                .put("index.number_of_shards", 3)
                .put("index.number_of_replicas", 2));
        // 可选参数，超时时间
        indexRequest.setTimeout(TimeValue.timeValueSeconds(2));
        // 字段和类型，可选
//        indexRequest.mapping(
//                "{\n" +
//                        "  \"properties\": {\n" +
//                        "    \"musicName\": {\n" +
//                        "      \"type\": \"text\"\n" +
//                        "    },\n" +
//                        "    \"author\": {\n" +
//                        "      \"type\": \"text\"\n" +
//                        "    },\n" +
//                        "    \"user\": {\n" +
//                        "      \"type\": \"text\"\n" +
//                        "    },\n" +
//                        "    \"area\": {\n" +
//                        "      \"type\": \"text\"\n" +
//                        "    }\n" +
//                        "  }\n" +
//                        "}",
//                XContentType.JSON);
//        indexRequest.mapping(
//                "{\n" +
//                        "  \"properties\": {\n" +
//                        "    \"musicName\": {\n" +
//                        "      \"type\": \"text\"\n" +
//                        "    },\n" +
//                        "    \"author\": {\n" +
//                        "      \"type\": \"text\"\n" +
//                        "    },\n" +
//                        "    \"user\": {\n" +
//                        "      \"type\": \"text\"\n" +
//                        "    },\n" +
//                        "    \"area\": {\n" +
//                        "      \"type\": \"text\"\n" +
//                        "    }\n" +
//                        "  }\n" +
//                        "}",
//                XContentType.JSON);
        try {
            // 同步方式
            client.indices().create(indexRequest, RequestOptions.DEFAULT);
        } catch (IOException e) {
            System.out.println("---创建ES索引失败---");
            e.printStackTrace();
        }
        return true;
    }

    @Override
    public List<Map<String, Object>> preciseQueryMusic(String registercode) throws IOException {
        SearchRequest request1 = new SearchRequest("music");
        //构建搜索条件
        SearchSourceBuilder builder = new SearchSourceBuilder();

        //条件判断，如果传入的属性为空的话则不执行该查询条件
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        boolQueryBuilder.must(QueryBuilders.matchQuery("registrationCode", registercode));

        builder.query(boolQueryBuilder);
        builder.timeout(new TimeValue(60, TimeUnit.SECONDS));

        request1.source(builder);
        SearchResponse searchResponse = client.search(request1, RequestOptions.DEFAULT);
        //解析结果
        ArrayList<Map<String, Object>> list = new ArrayList<>();
        for (SearchHit hit : searchResponse.getHits().getHits()) {
            Map<String, HighlightField> highlightFields = hit.getHighlightFields();
            Map<String, Object> sourceAsMap = hit.getSourceAsMap();  //没高亮的数据
            list.add(sourceAsMap);
        }
        return list;
    }

    @Override
    public List<Map<String, Object>> preciseQueryAuthorization(String authorizationCode) throws IOException {
        SearchRequest request1 = new SearchRequest("authorization");
        //构建搜索条件
        SearchSourceBuilder builder = new SearchSourceBuilder();

        //条件判断，如果传入的属性为空的话则不执行该查询条件
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        boolQueryBuilder.must(QueryBuilders.matchQuery("authorizationCode", authorizationCode));

        builder.query(boolQueryBuilder);
        builder.timeout(new TimeValue(60, TimeUnit.SECONDS));

        request1.source(builder);
        SearchResponse searchResponse = client.search(request1, RequestOptions.DEFAULT);
        //解析结果
        ArrayList<Map<String, Object>> list = new ArrayList<>();
        for (SearchHit hit : searchResponse.getHits().getHits()) {
            Map<String, HighlightField> highlightFields = hit.getHighlightFields();
            Map<String, Object> sourceAsMap = hit.getSourceAsMap();  //没高亮的数据
            list.add(sourceAsMap);
        }
        return list;
    }

    /**
     * 删除判断索引是否存在
     * @param index
     * @return
     */
    private boolean isIndexExist(String index) {
        GetIndexRequest request = new GetIndexRequest(index);
        try {
            boolean exists = client.indices().exists(request, RequestOptions.DEFAULT);
            if (exists) {
                return true;
            }
        } catch (IOException e) {
            System.out.println("===判断索引是否存在请求失败");
            e.printStackTrace();
        }
        return false;
    }

    /**
     * 删除索引
     * @param indexName
     */
    private void deleteIndex(String indexName) {
        DeleteIndexRequest request = new DeleteIndexRequest(indexName);
        request.timeout("2m");
        try {
            client.indices().delete(request, RequestOptions.DEFAULT);
        } catch (IOException e) {
            System.out.println("===删除索引失败===");
            e.printStackTrace();
        }
    }
}

